import React, { useEffect, useLayoutEffect, useMemo, useState } from "react";
import { MicroApp } from "../Core/MicroApp";
import { useApp } from "./Provider";

interface IMicroAppProviderProps {
    config: AppView.IMicroAppOption;
    app: MicroApp;
    children?: any;
}

interface IMicroAppJourneyData {
    currentJourney: AppView.IJourney;
    currentStep: AppView.IJourneyStep;
    currentStepState?: any;
    journeys: AppView.IJourney[];
    config: AppView.IMicroAppOption;
    stepHistory: AppView.IJourneyStepHistoryItem[];
}

const MicroAppContext = React.createContext<any>({});

const MicroAppProvider = (props: IMicroAppProviderProps) => {
    const [ config ] = useState(props.config);
    const [ currentJourney, setCurrentJourney ] = useState<AppView.IJourney>();
    const [ journeys, setJourneys ] = useState<AppView.IJourney[]>(props.app.getJourneys());
    const [ currentStep, setCurrentStep ] = useState<AppView.IJourneyStep>();
    const [ currentStepState, setCurrentStepState ] = useState(null);
    const rootApp = useApp();
    const microAppContext = useMemo(() => ({
        config,
        app: props.app,
        currentJourney,
        journeys,
        currentStep,
        currentStepState,
        stepHistory: props.app.getStepHistory()
    }), [config, props.app, currentJourney, journeys, currentStep, currentStepState]);
    useLayoutEffect(() => {
        (microAppContext.app as any).api = rootApp;
        (microAppContext.app as any).getPage = rootApp.getPage.bind(rootApp);
        (microAppContext.app as any).serviceApi = rootApp.serviceApi;
    }, [microAppContext, rootApp.getPage, rootApp.serviceApi]);
    useEffect(() => {
        const rmCurrentJourney = microAppContext.app.on("onCurrentJourneyChange", (journey, firstStep, option) => {
            setCurrentJourney(journey);
            setCurrentStepState(option?.state);
            setCurrentStep(firstStep);
        });
        const rmJourneys = microAppContext.app.on("onJourneyChange", (journeys) => {
            setJourneys(journeys);
        });
        const rmStepChange = microAppContext.app.on("onCurrentJourneyStepChange", (step, state) => {
            setCurrentStepState(state);
            setCurrentStep(step);
        });
        const rmExitJourney = microAppContext.app.on("onExitJourney", (ignoreGoHome) => {
            setCurrentJourney(undefined);
            ignoreGoHome && setCurrentStep(undefined);
        });
        return () => {
            rmCurrentJourney();
            rmJourneys();
            rmStepChange();
            rmExitJourney();
        }
    }, []);
    return (
        <MicroAppContext.Provider value={microAppContext}>
            {props.children}
        </MicroAppContext.Provider>
    );
};

export const createMicroAppProvider = (config: AppView.IMicroAppOption): React.ComponentType<any> => {
    const microApp = new MicroApp(config);
    return (props: any) => <MicroAppProvider {...props} config={config} app={microApp}/>;
};

export const useMicroApp = (): MicroApp & AppView.IMicroAppExtendsApi => {
    const microAppContext = React.useContext(MicroAppContext);
    if(!microAppContext.app) {
        console.error("MicroAppContext is not defined");
    }
    return microAppContext.app;
};

export const useJourneyData = (): IMicroAppJourneyData => {
    const microAppContext = React.useContext(MicroAppContext);
    if(!microAppContext.app) {
        console.error("MicroAppContext is not defined");
    }
    return {
        currentJourney: microAppContext.currentJourney,
        currentStep: microAppContext.currentStep,
        currentStepState: microAppContext.currentStepState,
        journeys: microAppContext.journeys,
        stepHistory: microAppContext.stepHistory,
        config: microAppContext.config
    };
};

export const useJourney = () => {
    const journeyData = useJourneyData();
    const microAppContext = React.useContext(MicroAppContext);
    if(!microAppContext.app) {
        console.error("MicroAppContext is not defined");
    }
    return useMemo(() => ({
        data: journeyData,
        api: microAppContext.app
    }), [journeyData]);
};
